package seatiger.tomcat.util.buf;

import java.io.IOException;
import java.io.Serializable;

/**
 * 字节块，可以对同一个buf进行标记
 */
public class ByteChunk implements Cloneable, Serializable {

    private byte[] buff;
    private int start;
    private int end;

    /**
     * 缓冲区的限制大小，如果没有设置，或者是-1，那么缓冲区可以无限增大
     * <p>
     * 如果到达缓冲区的限制大小，那么就需要刷出数据
     */
    private int limit = -1;


    /**
     * 当buff数据为空的时候，读取数据
     */
    public interface ByteInputChannel {
        /**
         * 读取数据
         *
         * @param cbuf
         * @param off
         * @param len
         * @return
         * @throws IOException
         */
        int realReadBytes(byte cbuf[], int off, int len) throws IOException;
    }

    /**
     * 写出数据
     */
    public interface ByteOutputChannel {
        void realWriteBytes(byte cbuf[], int off, int len) throws IOException;
    }

    private ByteInputChannel in = null;
    private ByteOutputChannel out = null;


    public ByteChunk() {

    }

    public ByteChunk(int initial) {
        allocate(initial);
    }

    /**
     * 通过 ByteInputChannel 读取数组，存入字节块中，并将数据复制到src中
     *
     * @param src
     * @param off
     * @param len
     * @return
     * @throws IOException
     */
    public int substract(byte src[], int off, int len) throws IOException {
        if (end - start == 0) {
            int n = in.realReadBytes(src, off, buff.length);
            if (n < -1) {
                return -1;
            }
        }
        int n = len;
        if (n > getLength()) {
            n = getLength();
        }
        System.arraycopy(buff, start, src, off, n);
        start += n;
        return n;
    }

    /**
     * 分配buffer
     *
     * @param initial
     */
    private void allocate(int initial) {
        if (buff == null || buff.length < initial) {
            buff = new byte[initial];
        }
    }

    public void setLimit(int limit) {
        this.limit = limit;
    }

    public void setByteInputChannel(ByteInputChannel in) {
        this.in = in;
    }

    public void setByteOutputChannel(ByteOutputChannel out) {
        this.out = out;
    }

    /**
     * 使用指定的buf设置信息
     */
    public void setBytes(byte[] b, int off, int len) {
        this.buff = b;
        this.start = off;
        this.end = start + len;
    }

    @Override
    public String toString() {
        if (buff == null) {
            return null;
        }
        if (end - start == 0) {
            return "";
        }
        return new String(buff, start, end - start);
    }

    public void recycle() {
        start = 0;
        end = 0;
    }

    /**
     * 获取字节数组中的有效数据
     *
     * @return
     */
    public int getLength() {
        return end - start;
    }

    public byte[] getBuff() {
        return buff;
    }

    public int getStart() {
        return start;
    }

    public int getEnd() {
        return end;
    }

    public void setEnd(int end) {
        this.end = end;
    }

    /**
     * 将指定的string 转换为字节数组
     *
     * @param value
     * @return
     */
    public static byte[] convertToBytes(String value) {
        byte[] result = new byte[value.length()];
        for (int i = 0; i < value.length(); i++) {
            result[i] = (byte) value.charAt(i);
        }
        return result;
    }

    /**
     * 添加数据 先不考虑溢出情况
     *
     * @param src
     * @param off
     * @param len
     */
    public void append(byte src[], int off, int len) throws IOException {
        makeSpace(len);
        //buf中剩余的容量，可以存放src字节数据，那么就存放
        //不需要刷新
        if (len <= limit - end) {
            System.arraycopy(src, off, buff, end, len);
            end += len;
            return;
        }

        //剩余buf中的容量 不能够存放len,需要提前刷出

        //buf中可存放的容量
        int avail = limit - end;
        System.arraycopy(src, off, buff, end, avail);
        end += avail;
        //先将一部分数据刷出
        flushBuffer();
        int remain = len - avail;
        while (remain >= limit - end) {
            out.realWriteBytes(src, (off + len) - remain, limit - end);
            remain = remain - (limit - end);
        }
        System.arraycopy(src, (off + len) - remain, buff, end, remain);
        end += remain;
    }

    /**
     * 需要根据设置的limit,来判断缓冲区是否需要扩容
     * 这里我们都将limit 设置成和buffer.length一样，所有就不考虑扩容 逻辑
     *
     * @param count
     */
    private void makeSpace(int count) {
        if (limit <= buff.length) {
            return;
        }
        //TODO 考虑扩容 扩容逻辑。。。。
        return;
    }

    public void flushBuffer() throws IOException {
        out.realWriteBytes(buff, start, end - start);
        end = start;
    }


    /**
     * 在 字节数组中找个某个字节的位置
     * @param src
     * @param srcOff
     * @param srcLen
     * @param myOff
     * @return
     */
    public int indexOf( String src, int srcOff, int srcLen, int myOff ) {
        char first=src.charAt( srcOff );
        int srcEnd = srcOff + srcLen;
        for( int i=myOff+start; i <= (end - srcLen); i++ ) {
            if( buff[i] != first ) continue;
            // found first char, now look for a match
            int myPos=i+1;
            for( int srcPos=srcOff + 1; srcPos< srcEnd; ) {
                if( buff[myPos++] != src.charAt( srcPos++ ))
                    break;
                if( srcPos==srcEnd ) return i-start; // found it
            }
        }
        return -1;
    }

    public int indexOf(char c, int starting) {
        int ret = indexOf( buff, start+starting, end, c);
        return (ret >= start) ? ret - start : -1;
    }

    public static int  indexOf( byte bytes[], int off, int end, char qq )
    {
        // Works only for UTF
        while( off < end ) {
            byte b=bytes[off];
            if( b==qq )
                return off;
            off++;
        }
        return -1;
    }
}
